import React, {CSSProperties, RefObject} from "react";
import {IReactionDisposer} from "mobx/lib/core/reaction";
import {NamePath, Rule} from "rc-field-form/lib/interface";
import _ from "lodash";
import {apply, DataComponentProp, DataComponentState, VJsonDataComponentBase, YvanEventDispatch} from "../..";
import {autorun, toJS} from "mobx";
import * as Extend from "../../extend";
import {Input as AntdInput, Form} from "antd";
import {ColProps} from "antd/lib/grid/col";
import {FormInstance} from "antd/lib/form/hooks/useForm";

export interface FormItemVJSon<CTL> {

    /**
     * form.item 样式
     */
    itemStyle?: CSSProperties

    /**
     * 是否显示冒号
     */
    colon?: boolean

    /**
     * 标题
     */
    label?: string

    /**
     * 绑定实体
     */
    bind?: string

    /**
     * 校验规则
     */
    rules?: Rule[]

    /**
     * 标签跨度
     */
    labelCol?: ColProps

    /**
     * 组件跨度
     */
    wrapperCol?: ColProps

    /**
     * 是否可见
     */
    visible?: boolean

    /**
     * 宽度
     */
    width?: number | string

    /**
     * 是否格式化规则
     */
    formatRules?: boolean

    /**
     * 是否被禁用
     */
    disabled?: boolean

    /**
     * 是否必填
     */
    required?: boolean

    /**
     * 获取焦点事件
     */
    onFocus?: (sender: CTL) => void

    /**
     * 离开焦点事件
     */
    onBlur?: (sender: CTL) => void
}

export interface FormItemBaseProp<CTL> extends FormItemVJSon<CTL>, DataComponentProp<CTL> {

}

export interface FormItemBaseState<CTL> extends DataComponentState {
    /**
     * 关联的表单实体
     */
    $formRef?: RefObject<FormInstance>
}

// @ts-ignore
export abstract class VJsonFormItemBase<CTL, JSON extends FormItemBaseProp<CTL>, S extends FormItemBaseState<CTL>> extends VJsonDataComponentBase<CTL, JSON, S> {
    static defaultProps = {
        ...VJsonDataComponentBase.defaultProps,
        visible: true,
        formatRules: true,
        rules: []
    }

    valueWatcherDisposer?: IReactionDisposer
    formItemName!: string
    defaultValue!: any

    protected constructor(props: any, defaultProps: any) {
        super(props);

        let value = ''
        this.formItemName = props.vjson.bind ? props.vjson.bind :
            props.$default.$parentBind + '.' + props.vjson.bindChild

        if (this.formItemName) {
            value = _.get(props.$context.scopeInstance, this.formItemName)
        } else {
            this.formItemName = _.uniqueId('name_')
        }

        _.defaults(
            this.props.vjson,
            defaultProps,
            VJsonFormItemBase.defaultProps
        )

        this.defaultValue = this.normalizeToControl(value)

        // @ts-ignore
        this.state = {
            ...this.state,
            $formRef: props.$default.$formRef
        }
    }

    get value() {
        return _.get(this.props.$context.scopeInstance, this.formItemName)
    }

    set value(v) {
        if (this.formItemName) {
            v = this.normalizeToEntity(v);
            _.set(this.props.$context.scopeInstance, this.formItemName, v)
        }
    }

    componentDidMount() {
        super.componentDidMount();
        const me = this

        this.valueWatcherDisposer = autorun(() => {
            let value = _.get(me.props.$context.scopeInstance, me.formItemName)
            if (Extend.isDebugMode()) {
                console.log('ValueWatch', this.toString(), '.value', '=', value)
            }
            value = this.normalizeToControl(value)

            const form = me.state.$formRef?.current;
            if (form) {
                form.setFields([
                    {
                        name: me.formItemName,
                        value: value
                    }
                ])
            }
        });
    }

    componentWillUnmount() {
        super.componentWillUnmount();

        if (this.valueWatcherDisposer) {
            this.valueWatcherDisposer();
        }
    }

    /**
     * 从控件值到实体 (control -> entity) 的转换 normalizeToEntity
     */
    normalizeToEntity(value: any) {
        return value
    }

    set disabled(value: boolean) {
        this.props.vjson.disabled = value
    }

    get disabled() {
        return this.props.vjson.disabled!
    }

    set required(value: boolean) {
        this.props.vjson.required = value
    }

    get required() {
        return this.props.vjson.required!
    }

    set label(value: string) {
        this.props.vjson.label = value
    }

    get label() {
        return this.props.vjson.label!
    }

    /**
     * 从实体值到控件 (entity -> control) 的转换 normalizeToControl
     */
    normalizeToControl(value: any) {
        return value
    }

    protected get _isRootFormItem() {
        return true
    }

    /**
     * 渲染子元素
     */
    protected abstract renderWrapper(): JSX.Element

    /**
     * 绑定值被更改时触发
     * @param e
     */
    protected abstract onValueChange(e: any): void

    /**
     * 获取 FormItem 的绑定相关的属性。
     * 如果是获取 rootFormItem, 但组件本身并不是以 rootFormitem 为最终校验属性的. 则不会返回任何校验逻辑、绑定名称等
     * @param isRootFormItem 是否用来给 RootFormItem 获取绑定属性用的
     */
    _getFormItemBindProperty(isRootFormItem: boolean) {
        const requiredRuleCommon = {
            required: this.props.vjson.required,
            message: (this.props.vjson.label ? '\'' + this.props.vjson.label + '\' ' : '字段') + '必须填写',
        }

        const requiredRuleText = {
            required: this.props.vjson.required,
            validator: async (_, value) => {
                if (this.props.vjson.required) {
                    if (!value || !value.trim()) {
                        return Promise.reject(new Error((this.props.vjson.label ? '\'' + this.props.vjson.label + '\' ' : '字段') + '必须填写'));
                    }
                }
                return Promise.resolve()
            }
        }

        let rules = [
            this.props.vjson.view === 'text' ? requiredRuleText : requiredRuleCommon,
            // @ts-ignore
            ...this.props.vjson.rules
        ]

        if (!this._isRootFormItem && isRootFormItem) {
            // 如果是获取 rootFormItem, 但组件本身并不是以 rootFormitem 为最终校验属性的. 则不会返回任何校验逻辑、绑定名称等
            return {
                required: this.props.vjson.required
            }
        }

        return {
            initialValue: this.defaultValue,
            name: this.formItemName,
            rules: rules,
            normalize: this.normalizeToControl.bind(this)
        }
    }

    render() {
        if (!this.props.vjson.visible) {
            return null
        }

        const rules = [
            {
                required: this.props.vjson.required,
                message: (this.props.vjson.label ? '\'' + this.props.vjson.label + '\' ' : '字段') + '必须填写'
            }
        ]

        return (
            // @ts-ignore
            <Form.Item key={this.key} view_id={this.key} aria-roledescription={this.view}
                       style={{width: this.props.vjson.width, ...apply(this, this.props.vjson.itemStyle)}}
                       {...this._getFormItemBindProperty(true)}
                       colon={apply(this, this.props.vjson.colon)}
                       labelCol={apply(this, this.props.vjson.labelCol)}
                       wrapperCol={apply(this, this.props.vjson.wrapperCol)}
                       label={apply(this, this.props.vjson.label)}
            >
                {
                    this.renderWrapper()
                }
            </Form.Item>
        )
    }
}